#!/usr/bin/env python
#
# strucs.py is part of pyStrips
# Copyright (C) - 2009 - Juan B. Cabral <jbcabral_89@yahoo.com.ar>

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

################################################################################
# DOCS
################################################################################

'''Structures for operate pyStrips'''


################################################################################
# IMPORTS
################################################################################

import common
import error

################################################################################
# STRUCT BASE
################################################################################

class StructBase(object):
    def __init__(self, name, statement):
        self.name = name.strip()
        self.statement = statement.strip()
        

################################################################################
# PREDICATE
################################################################################

class Predicate(StructBase):
    def __init__(self, name, args, statement):
        super(Predicate, self).__init__(name, statement)
        self.args = args
         
    def __eq__(self, other):
        return isinstance(other, Predicate) \
        and self.name == other.name \
        and len(self.args) == len(other.args)
      
    def __repr__(self):
        return str(self)
    
    def __str__(self):
        return "Predicate: %s %s (%s)" % (self.name,
                                          str(self.args),
                                          self.statement) 
                                          
    
################################################################################
# STATE
################################################################################

class State(StructBase):
    def __init__(self, stype, name, preds, statement):
        super(State, self).__init__(name, statement)
        self.stype = stype.strip()
        self.preds = preds
       
    def __iter__(self):
        return iter(self.preds)
       
    def __repr__(self):
        return str(self)
    
    def __str__(self):
        return "State: %s - %s (%s)" % (self.stype,
                                           self.name,
                                           self.statement)
        
        
################################################################################
# OPERATOR
################################################################################

class Operator(StructBase):
    def __init__(self, name, args, pre_list, del_list, add_list, statement):
        super(Operator, self).__init__(name, statement)
        self.args = args
        self.pre_list = pre_list
        self.del_list = del_list
        self.add_list = add_list
     
    def __call__(self, stk):
        print stk
       
    def __iter__(self):
        for p in self.pre_list:
            yield p
        for p in self.del_list:
            yield p    
        for p in self.add_list:
            yield p
            
    def __repr__(self):
        return str(self)
    
    def __str__(self):
        return "Operator: %s %s (%s)" % (self.name,
                                         str(self.args),
                                         self.statement)  


################################################################################
# STRUCTURE GROUP
################################################################################

class StructureGroup(object):
    def __init__(self, structures):
        self.init_states = []
        self.goal_states = []
        self.predicates = []
        self.operators = []
        for struct in structures:
            self.add_struct(struct)

    def __iter__(self):
        all = self.predicates + self.operators + self.init_states
        return iter(all)
        
    def add_struct(self, struct):
        if isinstance(struct, State):
            if struct.stype == common.RW_STATE_GOAL:
                self.goal_states.append(struct)
            elif struct.stype == common.RW_STATE_INIT:
                self.init_states.append(struct)
        elif isinstance(struct, Operator):
            self.operators.append(struct)
        elif isinstance(struct, Predicate):
            self.predicates.append(struct)
        else:
            msg = "struct must be an State, Operator \
                    or Predicate instance. Found %s" % type(struct)
            raise error.PyStripsError(msg, error.INTERNAL_ERROR, None)


################################################################################
# PY STRIPS STACK
################################################################################

class Stack(object):
    def __init__(self, limit, end_state):
        self._list = []
        self.limit = limit
        self.end_state = end_state
    
    def __repr__(self):
        return str(self)
    
    def __str__(self):
        return "Stack (%i): %s" % (self.limit, str(self._list))
    
    def _sort(self, p_list):
        sort_tuples = []
        for p in p_list:
            w = self.end_state.preds.count(p)
            sort_tuples.append((w, p))
        sort_tuples.sort()
        return [p for w, p in sort_tuples]
    
    def in_limit(self):
        return len(self._list) <= self.limit
    
    def push(self, s):
        if isinstance(s, list):
            s = list(s)
        if isinstance(s, Operator):
            self._list.append(s)
            s = list(s.pre_list)
        self._list.append(s)
    
    def pop(self):
        try:
            pop = self._list.pop()
            if isinstance(pop, list):
                pop = self._sort(pop)
            return pop
        except IndexError:
            return None

        
################################################################################
# PY STRIPS SOLUTION
################################################################################

class Solution(object):
    def __init__(self, init_state, goal_state):
        self.init_state = init_state
        self.goal_state = goal_state
        self._operators = []

    def __iter__(self):
        return iter(self._operators)

    def add_op(self, op):
        self._operators.insert(0, op)
        
    @property
    def operators(self):
        return tuple(self._operators)

################################################################################
# MAIN
################################################################################
    
if __name__ == '__main__':
    print(__doc__)
